package modele.worldAgent;

import java.awt.Color;
import java.util.ArrayList;

import utility.Position;

import modele.Square;
import modele.World;

public abstract class Agent{

	public final static int SHEEP = 0;
	public final static int WOLF = 1;
	public final static int PATOU = 2;
	public final static int NBAGENT = 3;
	
	public final static int ATTRACTSIGNE = -1;
	public final static int REPULSESIGNE = 1;
	
	
	
	
	protected int[] agentWeight;
	protected int[] stateWeight;
	protected int[] secondaryStateWeight;
	protected int[] distanceWeight;
	
	enum Direction{
		NORTH(0),
		EAST (1),
		SOUTH(2),
		WEST (3);
		
		public final static int nbDirection = 4;
	
		
		/** L'attribut qui contient la valeur associé à l'enum */
		private final int value;
	 
		/** Le constructeur qui associe une valeur à l'enum */
		private Direction(int value) {
			this.value = value;
		}
	 
		/** La méthode accesseur qui renvoit la valeur de l'enum */
		public int getValue() {
			return this.value;
		}
		
		/** La méthode accesseur qui renvoit la valeur de SOUTH pour NORTH et EAST pour WEST et vice et versa
		 * 
		 * */
		public int getInverseValue() {
			return (this.value + 2) % 4;
		}
		
		
		
		
	};
	
	
	/**
	 * 1 = NORTH
	 * 2 = EAST
	 * 3 = SOUTH
	 * 4 = OUEST
	 * 
	 * la taille du tableau indique le nombre de mouvement (la vitesse) de l'agent
	 */
	public ArrayList<Direction> directions;
	
	
	
	World world;
	int posX;
	int posY;
	boolean mustDied;
	
	
	public abstract void step();
	public abstract int getId();
	public abstract Color getColor();
	public abstract int getMaxSpeed();
	public abstract int getWeight(int posX, int posY, int distance);
	protected abstract void initWeight();
	public abstract int[] normalizeMovement(int[] movement);
	public abstract void survive();
	public abstract void setPosition(int x, int y);
	
	
	
	public Agent(int posX, int posY, World w)
	{
		this.posX = posX;
		this.posY = posY;
		this.world = w;
		mustDied=false;
		initWeight();
	}

	
	public int getPosX() {
		return posX;
	}
	
	
	public Agent getAgent(int posX, int posY){
		return getWorld().getAgent(posX,posY);
	}
	public int getPosY() {
		return posY;
	}
	
	
	
	public World getWorld(){
		return this.world;
	}
	
	public Square getSquare(){
		return world.getSquare(posX, posY);
	}
	
	
	
	
	public void setDie(){
		world.removeAgent(this);
	}
	
	
	
	protected Position getFinalPosition(int[] movement ){
		int deltaX = 0;
		int deltaY = 0;
		if(movement.length == Direction.nbDirection){
			deltaX = movement[Direction.EAST.getValue()]
					- movement[Direction.WEST.getValue()];
			deltaY = movement[Direction.SOUTH.getValue()]
					- movement[Direction.NORTH.getValue()];
		}
		int posX = deltaX + this.posX;
		int posY = deltaY + this.posY;
		posX = Math.max(0, posX);
		posX = Math.min(world.getWidth()-1, posX);
		posY = Math.max(0, posY);
		posY = Math.min(world.getWidth()-1, posY);
		return new Position(posX, posY); 
	}
	
	
	
	protected int getSpeedMovement(int[] movement ){
		if(movement.length != Direction.nbDirection){
			return 0;
		}
		int deltaY = movement[Direction.NORTH.getValue()]
				- movement[Direction.NORTH.getValue()];
		int deltaX = movement[Direction.EAST.getValue()]
				- movement[Direction.WEST.getValue()];
		return Math.max(Math.abs(deltaX), Math.abs(deltaY));
	}
	
	
	/**
	 * retourne le mouvement nord sud ouest est qu'il faut pour rejoindre l'agent à partir de x y;
	 * @param posX
	 * @param posY
	 * @return
	 */
	protected int[] getMovementToAgent(int posX, int posY){
		int[] result = new int[Direction.nbDirection];
		for (int i = 0 ; i < Direction.nbDirection ; i++){
			result[i] = 0;
		}
		int deltaX =  this.posX - posX;
		if(deltaX < 0){
			result[Direction.WEST.getValue()] = Math.abs(deltaX);
		}
		else{
			result[Direction.EAST.getValue()] = Math.abs(deltaX);
		}
		int deltaY =  this.posY - posY;
		if(deltaY < 0){
			result[Direction.NORTH.getValue()] = Math.abs(deltaY);
		}
		else{
			result[Direction.SOUTH.getValue()] = Math.abs(deltaY);
		}
		return result;
	}
	
	protected int[] applyWeight(int weight , int[] movement){
		if(movement.length != Direction.nbDirection){
			return null;
		}
		int[] result = new int[Direction.nbDirection];
		if(weight != 0 && weight/Math.abs(weight) == ATTRACTSIGNE){
			result[Direction.NORTH.getValue()] = -weight * movement[Direction.NORTH.getInverseValue()];
			result[Direction.EAST.getValue()] = -weight * movement[Direction.EAST.getInverseValue()];
			result[Direction.SOUTH.getValue()] = -weight * movement[Direction.SOUTH.getInverseValue()];
			result[Direction.WEST.getValue()] = -weight * movement[Direction.WEST.getInverseValue()];
		}
		else{
			result[Direction.NORTH.getValue()] = weight * movement[Direction.NORTH.getValue()];
			result[Direction.EAST.getValue()] = weight * movement[Direction.EAST.getValue()];
			result[Direction.SOUTH.getValue()] = weight * movement[Direction.SOUTH.getValue()];
			result[Direction.WEST.getValue()] = weight * movement[Direction.WEST.getValue()];
		}
		return result;
	}
	
	
	/**
	 * ne marche qu'avec un tableau de 4 direction N E S W;
	 * @param movement
	 * @return
	 */
	public static boolean isStatic(int[] movement){
		if(movement.length != 4){
			return false;
		}
		int deltaX = Math.abs(movement[Direction.NORTH.getValue()] - movement[Direction.NORTH.getInverseValue()]);
		int deltaY = Math.abs(movement[Direction.EAST.getValue()] - movement[Direction.EAST.getInverseValue()]);
		
		return(deltaX == 0 && deltaY ==0);
	}
	
	/**
	 * ajoute m2 dans m1;
	 * @param m1
	 * @param m2
	 */
	protected int[] addMovement(int[] m1 , int[] m2){
		if( m1.length != Direction.nbDirection || m2.length != Direction.nbDirection ){
			return null;
		}
		for(int i = 0 ; i < Direction.nbDirection ; i++ ){
			m1[i] += m2[i];
		}
		return m1;
	}

	
	public static void main(String[] args){
		System.out.println(Direction.NORTH.getValue());
		System.out.println(Direction.EAST.getValue());
		System.out.println(Direction.SOUTH.getValue());
		System.out.println(Direction.WEST.getValue());
		
		
		int[] m = new int[4];
		m[0] = 0;
		m[1] = 1;
		m[2] = 0;
		m[3] = 1;
		
		
		System.out.println(isStatic(m));
	}
	

}
